package client

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"ubbc/internal/config"
	"ubbc/internal/interfaces"
	"ubbc/pkg/logger"
)

// OllamaClient Ollama API客户端结构体
// 提供调用Ollama API进行图片内容分析的功能
type OllamaClient struct {
	config     *config.OllamaConfig // Ollama配置
	httpClient *http.Client         // HTTP客户端
	logger     *logger.Logger       // 日志记录器
	rules      []config.Rule        // 持有的规则
}

// NewOllamaClient 创建新的Ollama客户端
func NewOllamaClient(cfg *config.OllamaConfig, log *logger.Logger, rules []config.Rule) *OllamaClient {
	return &OllamaClient{
		config: cfg,
		httpClient: &http.Client{
			Timeout: cfg.Timeout.ToDuration(),
		},
		logger: log,
		rules:  rules,
	}
}

// SetRules 注入规则
func (c *OllamaClient) SetRules(rules []config.Rule) {
	c.rules = rules
}

// AnalyzeImage 分析图片内容 - 优化版本
// 使用单次AI调用完成所有规则检查，提升性能和并发处理能力
// 返回json字符串，包含overallResult、命中rules-name集合、详细判定
func (c *OllamaClient) AnalyzeImage(ctx context.Context, imageURL, requestID string) (string, error) {
	reqLogger := c.logger.WithRequestID(requestID)

	// 构建智能化的单次分析prompt
	prompt := c.buildComprehensivePrompt(imageURL)
	
	// 单次AI调用完成所有分析
	aiResponse, err := c.askOllama(ctx, prompt)
	if err != nil {
		reqLogger.Warn("AI analysis failed, using fallback", map[string]interface{}{"error": err.Error()})
		return c.fallbackAnalysis(ctx, imageURL, requestID)
	}

	// 尝试解析AI返回的结构化结果
	result, err := c.parseAIResponse(aiResponse, reqLogger)
	if err != nil {
		reqLogger.Warn("Failed to parse AI response, using fallback", map[string]interface{}{"error": err.Error(), "response": aiResponse})
		return c.fallbackAnalysis(ctx, imageURL, requestID)
	}

	resultJson, err := json.Marshal(result)
	if err != nil {
		return "", fmt.Errorf("failed to marshal result: %w", err)
	}

	reqLogger.Debug("AI analysis completed", map[string]interface{}{
		"violated": result["violated"],
		"rules_count": len(c.rules),
	})

	return string(resultJson), nil
}

// askOllama 辅助方法，向Ollama发送一次对话，返回content
func (c *OllamaClient) askOllama(ctx context.Context, prompt string) (string, error) {
	ollamaReq := map[string]interface{}{
		"model": c.config.Model,
		"messages": []map[string]interface{}{
			{"role": "user", "content": prompt},
		},
	}
	reqBody, err := json.Marshal(ollamaReq)
	if err != nil {
		return "", fmt.Errorf("failed to marshal request: %w", err)
	}
	var lastErr error
	for attempt := 0; attempt <= c.config.MaxRetries; attempt++ {
		if attempt > 0 {
			backoffDuration := time.Duration(attempt) * time.Second
			time.Sleep(backoffDuration)
		}
		req, err := http.NewRequestWithContext(ctx, "POST", c.config.APIURL+"/v1/chat/completions", bytes.NewBuffer(reqBody))
		if err != nil {
			lastErr = fmt.Errorf("failed to create request: %w", err)
			continue
		}
		req.Header.Set("Content-Type", "application/json")
		if c.config.APIKey != "" {
			req.Header.Set("Authorization", "Bearer "+c.config.APIKey)
		}
		resp, err := c.httpClient.Do(req)
		if err != nil {
			lastErr = fmt.Errorf("failed to send request: %w", err)
			continue
		}
		defer resp.Body.Close()
		respBody, err := io.ReadAll(resp.Body)
		if err != nil {
			lastErr = fmt.Errorf("failed to read response: %w", err)
			continue
		}
		if resp.StatusCode != http.StatusOK {
			lastErr = fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(respBody))
			continue
		}
		var respObj struct {
			Choices []struct {
				Message struct {
					Content string `json:"content"`
				} `json:"message"`
			} `json:"choices"`
		}
		if err := json.Unmarshal(respBody, &respObj); err != nil {
			lastErr = fmt.Errorf("failed to parse response: %w", err)
			continue
		}
		if len(respObj.Choices) == 0 || respObj.Choices[0].Message.Content == "" {
			lastErr = fmt.Errorf("empty content in response")
			continue
		}
		return respObj.Choices[0].Message.Content, nil
	}
	return "", fmt.Errorf("failed to get response after %d attempts: %w", c.config.MaxRetries+1, lastErr)
}

// buildComprehensivePrompt 构建综合性分析prompt - 简化版本
func (c *OllamaClient) buildComprehensivePrompt(imageURL string) string {
	var rulesDesc strings.Builder
	
	for i, rule := range c.rules {
		if !rule.Activate {
			continue
		}
		rulesDesc.WriteString(fmt.Sprintf("规则%d-%s: ", i+1, rule.RulesName))
		var conditions []string
		for _, cond := range rule.Conditions {
			if cond.Value {
				conditions = append(conditions, cond.Content)
			}
		}
		rulesDesc.WriteString(fmt.Sprintf("检查是否包含[%s]\n", strings.Join(conditions, ", ")))
	}

	prompt := fmt.Sprintf(`请分析这张图片的内容: %s

分析完图片后，请检查是否违反以下规则：
%s

请用JSON格式回复，包含以下字段：
- description: 图片内容描述
- violated: 是否违规(true/false)  
- violated_rules: 违规的规则名称数组
- details: 每个规则的检查详情

示例格式：
{"description":"图片描述","violated":false,"violated_rules":[],"details":[{"rule_name":"规则名","violated":false,"matched_conditions":[]}]}`, imageURL, rulesDesc.String())

	return prompt
}

// parseAIResponse 解析AI返回的结构化响应
func (c *OllamaClient) parseAIResponse(aiResponse string, reqLogger *logger.RequestLogger) (map[string]interface{}, error) {
	// 清理响应，移除可能的markdown标记
	cleanResponse := strings.TrimSpace(aiResponse)
	cleanResponse = strings.TrimPrefix(cleanResponse, "```json")
	cleanResponse = strings.TrimPrefix(cleanResponse, "```")
	cleanResponse = strings.TrimSuffix(cleanResponse, "```")
	cleanResponse = strings.TrimSpace(cleanResponse)

	var result map[string]interface{}
	if err := json.Unmarshal([]byte(cleanResponse), &result); err != nil {
		return nil, fmt.Errorf("failed to parse JSON response: %w", err)
	}

	// 验证必要字段
	if _, ok := result["violated"]; !ok {
		return nil, fmt.Errorf("missing 'violated' field in response")
	}
	if _, ok := result["description"]; !ok {
		return nil, fmt.Errorf("missing 'description' field in response")
	}

	return result, nil
}

// fallbackAnalysis 降级分析方法
func (c *OllamaClient) fallbackAnalysis(ctx context.Context, imageURL, requestID string) (string, error) {
	reqLogger := c.logger.WithRequestID(requestID)
	
	// 使用简单的描述性prompt
	descPrompt := fmt.Sprintf("请分析这张图片的内容，描述你看到的文字、logo、品牌等信息。图片URL: %s", imageURL)
	desc, err := c.askOllama(ctx, descPrompt)
	if err != nil {
		return "", fmt.Errorf("fallback analysis failed: %w", err)
	}

	// 使用本地字符串匹配进行规则检查
	type RuleResult struct {
		RuleName   string   `json:"rule_name"`
		Violated   bool     `json:"violated"`
		Conditions []string `json:"matched_conditions"`
	}
	
	var violatedRuleNames []string
	var ruleResults []RuleResult
	overallViolated := false

	descLower := strings.ToLower(desc)
	
	for _, rule := range c.rules {
		if !rule.Activate {
			continue
		}
		
		matchedConds := []string{}
		violated := false
		
		for _, cond := range rule.Conditions {
			if !cond.Value {
				continue
			}
			
			condStr := strings.TrimSpace(strings.ReplaceAll(cond.Content, "\n", ""))
			condLower := strings.ToLower(condStr)
			
			if strings.Contains(descLower, condLower) {
				matchedConds = append(matchedConds, cond.Content)
				violated = true
				reqLogger.Debug("Fallback rule matched", map[string]interface{}{
					"rule": rule.RulesName,
					"condition": cond.Content,
				})
			}
		}
		
		if violated {
			overallViolated = true
			violatedRuleNames = append(violatedRuleNames, rule.RulesName)
		}
		
		ruleResults = append(ruleResults, RuleResult{
			RuleName:   rule.RulesName,
			Violated:   violated,
			Conditions: matchedConds,
		})
	}

	result := map[string]interface{}{
		"violated":       overallViolated,
		"violated_rules": violatedRuleNames,
		"details":        ruleResults,
		"description":    desc,
	}
	
	resultJson, err := json.Marshal(result)
	if err != nil {
		return "", fmt.Errorf("failed to marshal fallback result: %w", err)
	}
	
	reqLogger.Info("Fallback analysis completed", map[string]interface{}{
		"violated": overallViolated,
		"matched_rules": len(violatedRuleNames),
		"description": desc,
	})
	
	return string(resultJson), nil
}

// 确保 OllamaClient 实现 ImageModelClientInterface
var _ interfaces.ImageModelClientInterface = (*OllamaClient)(nil)
